package com.course.file.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.AppendObjectRequest;
import com.aliyun.oss.model.AppendObjectResult;
import com.aliyun.oss.model.ObjectMetadata;
import com.course.file.config.AliyunOssConfig;
import com.course.file.service.UploadService;
import com.course.server.dto.FileDto;
import com.course.server.enums.FileUseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * @author: Durian
 * @date: 2021/5/22 14:34
 */
@Slf4j
@Service("aliyunOss")
@ConditionalOnProperty(prefix = "upload", name = "address", havingValue = "aliyunOss")
public class AliyunOssService implements UploadService {

    @Resource
    private AliyunOssConfig aliyunOssConfig;

    /**
     * 使用阿里云OSS的追加文件上传
     *
     * @param file    文件
     * @param fileDto 文件dto
     * @return 文件访问全路径
     * @throws IOException IOException
     */
    @Override
    public String upload(MultipartFile file, FileDto fileDto) throws IOException {
        // 创建OSSClient实例。
        log.info("===========创建ossClient实例============");
        OSS ossClient = new OSSClientBuilder().build(aliyunOssConfig.getEndpoint(), aliyunOssConfig.getAccessKeyId(), aliyunOssConfig.getAccessKeySecret());
        log.info("===========创建ossClient实例完毕============");
        ObjectMetadata meta = new ObjectMetadata();
        // 指定上传的内容类型。
        meta.setContentType(file.getContentType());
        // 通过AppendObjectRequest设置多个参数。
        // 设置文件名称
        String dir = FileUseEnum.get(fileDto.getUse()).name().toLowerCase();
        String key = fileDto.getKey();
        String suffix = fileDto.getSuffix();
        String path = dir + "/" + key + "." + suffix;
        log.info("文件【{}】保存路径【{}】", fileDto.getName(), path);

        AppendObjectRequest appendObjectRequest = new AppendObjectRequest(aliyunOssConfig.getBucket(), path, new ByteArrayInputStream(file.getBytes()), meta);

        // 通过AppendObjectRequest设置单个参数。
        // 设置Bucket名称。
        //appendObjectRequest.setBucketName("<yourBucketName>");
        // 设置Object名称。即不包含Bucket名称在内的Object的完整路径，例如example/test.txt。
        //appendObjectRequest.setKey("<yourObjectName>");
        // 设置待追加的内容。有两种可选类型：InputStream类型和File类型。这里为InputStream类型。
        //appendObjectRequest.setInputStream(new ByteArrayInputStream(content1.getBytes()));
        // 设置待追加的内容。有两种可选类型：InputStream类型和File类型。这里为File类型。
        //appendObjectRequest.setFile(new File("<yourLocalFile>"));
        // 指定文件的元信息，第一次追加时有效。
        //appendObjectRequest.setMetadata(meta);

        // 设置文件的追加位置。
        appendObjectRequest.setPosition((long) ((fileDto.getShardIndex() - 1) * fileDto.getShardSize()));
        log.info("ossClient追加文件, position=【{}】", (fileDto.getShardIndex() - 1) * fileDto.getShardSize());
        AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);
        // 文件的64位CRC值。此值根据ECMA-182标准计算得出。
        log.info(appendObjectResult.getObjectCRC());
        log.info("阿里云OSS追加上传文件【{}】完成: {}", file.getName(), appendObjectResult.getObjectCRC());

        // 关闭OSSClient。
        ossClient.shutdown();
        // 返回文件访问全路径
        return aliyunOssConfig.getOssDomain() + path;
    }

    @Override
    public String check(FileDto fileDto) {
        String dir = FileUseEnum.get(fileDto.getUse()).name().toLowerCase();
        String key = fileDto.getKey();
        String suffix = fileDto.getSuffix();
        String path = dir + "/" + key + "." + suffix;
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(aliyunOssConfig.getEndpoint(), aliyunOssConfig.getAccessKeyId(), aliyunOssConfig.getAccessKeySecret());
        // 判断文件是否存在。如果返回值为true，则文件存在，否则存储空间或者文件不存在。
        // 设置是否进行重定向或者镜像回源。默认值为true，表示忽略302重定向和镜像回源；如果设置isINoss为false，则进行302重定向或者镜像回源。
        //boolean isINoss = true;
        // 填写Bucket名称和Object完整路径。Object完整路径中不能包含Bucket名称。
        boolean found = ossClient.doesObjectExist(aliyunOssConfig.getBucket(), path);
        //boolean found = ossClient.doesObjectExist("examplebucket", "exampleobject.txt", isINoss);
        log.info("OSS查找key={}文件结果：{}", path, found);

        // 关闭OSSClient。
        ossClient.shutdown();

        return found ? aliyunOssConfig.getOssDomain() + path : null;
    }

}
